package com.java.lambda.optional;

import com.java.lambda.model.Author;
import com.java.lambda.model.Book;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;


public class OptionalDemo {
    public static void main(String[] args) {
        
        testMap();
//        testIsPresent();
//        testFilter();

//        创建 , 采用静态方法ofNullable把要创建的数据传入即可。
//        Author author = getAuthor();
//        Optional<Author> authorOptional = Optional.ofNullable(author);
//        authorOptional.ifPresent(author1 -> System.out.println(author1.getName()));


//        消费
//        Optional<Author> authorOptional = getAuthorOptional();
//        try {
//            Author author = authorOptional.orElseThrow(() -> new RuntimeException("数据为null"));
//            System.out.println(author);
//        } catch (Throwable throwable) {
//            throwable.printStackTrace();
//        }


//        Author author = authorOptional.orElseGet(() -> new Author(2L,"三更",15,"一个从菜刀中明悟哲理的祖安人",null));
//        System.out.println(author.getName());

//        authorOptional.ifPresent(author -> System.out.println(author.getName()));

//        Author author = getAuthor();
//        Optional<Author> authorOptional = Optional.of(author);
//        authorOptional.ifPresent(author1 -> System.out.println(author.getName()));
    }
    
    /**
     * map方法被用来从Optional<Author>转换到Optional<List<Book>>。
     * map方法允许你对Optional内部的值应用函数转换，并返回一个新的Optional对象，
     * 这个新的Optional要么包含转换后的结果，要么为空（如果原来的Optional为空）。
     * 具体来说，map方法接收一个函数作为参数，该函数将应用于Optional中的值。
     * 在这个例子中，函数是 author -> author.getBooks()，它尝试从Author对象中获取书籍列表。
     *
     * 使用map的好处在于它允许你在处理Optional的同时，对其内部的值进行转换，而不需要显式地从Optional中取出值。
     * 这有助于保持代码的简洁性，并且避免了可能出现的NullPointerException。
     * 此外，map与flatMap的区别在于，map会返回Optional的嵌套结构，而flatMap则不会。
     * 在某些情况下，如果getBooks()方法返回的是Optional<List<Book>>而不是直接的List<Book>，那么应该使用flatMap来避免嵌套的Optional。
     * 总结来说，map在这里的作用是对Optional<Author>中的Author对象应用一个函数，
     * 从而获取Author的书籍列表，并返回一个新的Optional<List<Book>>。
     */
    private static void testMap() {
        Optional<Author> authorOptional = getAuthorOptional();
        Optional<List<Book>> optionalBooks = authorOptional.map(author -> author.getBooks());
        optionalBooks.ifPresent(books -> System.out.println(books));
    }
    
    /**
     * 段代码使用isPresent方法来检查Optional对象是否包含一个非null的值。
     * isPresent是一个返回布尔值的方法，如果有值则返回true，如果没有值（即Optional是空的）则返回false。
     * 在这段代码中，testIsPresent方法首先通过getAuthorOptional()方法获取了一个Optional<Author>实例。
     * 接着，它使用isPresent来检查是否有实际的对象存储在这个Optional中。
     * 如果有（即isPresent返回true），那么它就会通过get()方法来获取存储的对象，并打印出作者的名字和年龄。
     * 使用isPresent和get组合的方式是在确保Optional中有值的情况下才去获取这个值。
     * 这是为了避免直接使用get()而引发的NoSuchElementException异常，因为如果Optional是空的，直接调用get()会导致这个异常。
     * 然而，在现代Java编程实践中，更推荐使用Optional提供的其他方法来以一种更加安全的方式处理可能存在的null值，
     * 比如ifPresent或者orElse、orElseGet、orElseThrow等方法。这些方法不仅能够避免异常，还能让代码更加易读和安全。
     */
    private static void testIsPresent() {
        Optional<Author> authorOptional = getAuthorOptional();
        if (authorOptional.isPresent()) {
            System.out.println(authorOptional.get().getName());
            System.out.println(authorOptional.get().getAge());
            System.out.println(authorOptional.get().getAge());
        }
    }
    
    /**
     * 在Java中，Optional类是一个可以为null的容器对象。如果一个值存在则保存该值，否则就简单地保存一个null。Optional提供了一种优雅的方式来处理可能为null的值，避免了空指针异常。
     * filter方法用于过滤Optional中的值，它接受一个谓词（即一个条件判断函数），如果该谓词对当前值返回true，则保留该值；否则将当前Optional转换为空Optional。
     * ifPresent是一个方法，它接收一个消费型函数（Consumer）作为参数。如果Optional有值（非空），则会使用提供的函数消费这个值；如果Optional是空的，则什么也不做。
     * 在你的代码示例中，testFilter方法首先获取了一个Optional<Author>实例。然后调用filter方法来检查作者的年龄是否大于88岁。
     * 如果是的话，filter会返回一个包含相同作者的新Optional对象；如果不是，则返回一个空的Optional对象。
     * 接下来的ifPresent部分只有当filter返回的是非空的Optional（即作者年龄确实大于88岁）时才会执行，并打印出作者的名字。
     * 这里使用ifPresent是因为你只关心那些年龄超过88岁的作者，并且只想对这些符合条件的作者进行操作（在这里是打印名字）。
     * 如果Optional为空，也就是没有找到符合条件的作者，那么ifPresent中的代码块就不会被执行。这种方式避免了不必要的操作，并且使得代码更加清晰简洁。
     */
    private static void testFilter() {
        Optional<Author> authorOptional = getAuthorOptional();
        authorOptional.filter(author -> author.getAge() > 88).ifPresent(author -> System.out.println(author.getName()));
        
    }
    
    public static Optional<Author> getAuthorOptional(){
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        //书籍列表
        List<Book> books1 = new ArrayList<>();
        books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀划分了爱恨"));
        books1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述如何从失败中明悟真理"));
        author.setBooks(books1);
        return Optional.ofNullable(author);
    }
    
    
    public static Author getAuthor(){
        Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        return author;
    }
}
